/*
 * Copyright (c) 2017-2021, Lindenis Tech. Ltd.
 * All rights reserved.
 *
 * File:
 *
 * Description:
 *
 * Author:
 *      xiaoshujun@lindeni.com
 *
 * Create Date:
 *      2021/03/16
 *
 * History:
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>

#include "osal_log.h"
#include "osal_common.h"
#include "mpp_camera.h"
#include "lindcomponent.h"

#include "lindsink.h"
#include "lindnet.h"

typedef struct _sample_lindsink_ctx_t
{
    lindsink_t *            p_sink;
    rtpsink_config_t        rtp_cfg;

    _handle_t               h_camera;
    camera_config_t         camera_cfg;
    preview_config_t        preview_cfg;
    venc_config_t           venc_cfg;
} sample_lindsink_ctx_t;

static int _lindsink_data_cb(void *user, int msg, void * ext1, void * ext2)
{
    sample_lindsink_ctx_t * p_ctx = (sample_lindsink_ctx_t *)user;
    lindsink_t * p_sink = p_ctx->p_sink;
    switch (msg) {
        case LD_CAMERA_MSG_CB_ES:
        {
            av_frame2_t * p_frame = (av_frame2_t *)ext1;
            logv("get frame format: %d, size: %d", p_frame->format, p_frame->size[0]);
            p_sink->write(p_sink, (av_frame2_t *)ext1);
            break;
        }
        default:
        {
            loge("unknown msg: %d", msg);
            break;
        }
    }

    return 0;
}

int test_rtpsink(sample_lindsink_ctx_t * p_ctx)
{
    int ret = 0;

    // start rtpsink
    p_ctx->p_sink = lindsink_create(LINDSINK_RTP, &p_ctx->rtp_cfg);
    if (!p_ctx->p_sink)
    {
        loge("lindsink_create failed");
        return -1;
    }

    // start camera source
    p_ctx->h_camera = mpp_cam_create(0);
    if (!p_ctx->h_camera)
    {
        goto _exit1_;
    }
    mpp_cam_set_params(p_ctx->h_camera, &p_ctx->camera_cfg);
    mpp_cam_venc_set_params(p_ctx->h_camera, 0, &p_ctx->venc_cfg);
    ret = mpp_cam_venc_start(p_ctx->h_camera, 0);
    if (ret < 0)
    {
        loge("mpp_cam_venc_start failed");
        goto _exit2_;
    }

    while(1)
    {
        signed char key_val;
        ret = wait_input_char(&key_val, 100000);
        if (ret < 0)
        {
            break;
        }
        else if (ret == 0)
        {
            continue;
        }

        if (key_val > 0 && key_val)
        {
            if (key_val != '\n')
            {
                printf("********* key_val: %c ********** \n", key_val);
            }

            if (key_val == 'q' || key_val == 'Q')
            {
                break;
            }
        }
    }

    mpp_cam_venc_stop(p_ctx->h_camera, 0);

_exit2_:
    mpp_cam_destroy(p_ctx->h_camera);

_exit1_:
    p_ctx->p_sink->close(p_ctx->p_sink);

    return 0;
}

static void _lindrtp_print_usage(char * this)
{
    printf("\033[32m");
    printf("Usage: \n");
    printf("    %s <options>. \n", this);
    printf("        -i [ip]         : the ip addr of the rtp stream receiver \n");
    printf("        -p [port]       : the port of the rtp stream receiver, default '9980' \n");
    printf("        -pt [payload]   : payload type, default '96' \n");
    printf("        -udp/-rdt       : use udp or rdt protocol, default 'udp' \n");
    printf("                        : If use 'rdt' protocol, should run 'sample_lindsource' before 'sample_lindsink'. \n");
    printf("        -h264/-h265     : video encode type, default 'h264' \n");
    printf("        -br [bitrate]   : video encode bitrate, default '2000000' \n");
    printf("        -s [w h]        : video capture size, default '1920 1080' \n");
    printf("        -vs [w h]       : video encode size, default '1920 1080' \n");
    printf("    such as: %s -i 192.168.1.2 -p 9980 -rdt \n\n", this);
    printf("\033[0m\n");
}

#ifdef MELIS_OS
static int main_melis(int argc, char **argv)
#else
int main(int argc, char **argv)
#endif
{
    int ret = 0;
    int i = 0;
    sample_lindsink_ctx_t context = {0};
    int port = 0;
    char * ip = NULL;

    if ((argc == 2)
        && (!strcmp(argv[1], "-h")))
    {
        _lindrtp_print_usage(argv[0]);
        return 0;
    }

    /*
     * capture parameters
     */
    context.camera_cfg.msg_cb = _lindsink_data_cb;
    context.camera_cfg.user = (void*)&context;
    context.camera_cfg.cap_width = 1920;
    context.camera_cfg.cap_height = 1080;
    context.camera_cfg.framerate = 25;
    context.camera_cfg.cap_width_sub = 320;
    context.camera_cfg.cap_height_sub = 180;
    context.camera_cfg.flip = 0;
    context.camera_cfg.mirror = 0;

    /*
     * preview parameters
     */
    context.preview_cfg.rotate = 0;
    context.preview_cfg.pos.left = 0;
    context.preview_cfg.pos.top = 0;
    context.preview_cfg.pos.width = 0;
    context.preview_cfg.pos.height = 0;

    /*
     * encode parameters
     */
    context.venc_cfg.venc_type = AV_ENC_TYPE_H264;
    context.venc_cfg.profile = 1;
    context.venc_cfg.venc_width = 1920;
    context.venc_cfg.venc_height = 1080;
    context.venc_cfg.bitrate = 2000000;
    context.venc_cfg.framerate = 25;    // same as the capture framerate
    context.venc_cfg.gop = 30;
    context.venc_cfg.venc_rotate = 0;
    context.venc_cfg.venc_mirror = 0;
    context.venc_cfg.mux_type = AV_MUX_TYPE_NONE;
    context.venc_cfg.rc_mode = 0;
    context.venc_cfg.min_qp = 5;
    context.venc_cfg.max_qp = 45;
    context.venc_cfg.iframe_attach_spspps = 1;

    /*
     * sink parameters
     */
    context.rtp_cfg.ip = "0.0.0.0";
    context.rtp_cfg.name = "test";
    context.rtp_cfg.port = 9980;
    context.rtp_cfg.venc_type = AV_ENC_TYPE_H264;
    context.rtp_cfg.protocol = LINDNET_TYPE_UDP;
    context.rtp_cfg.payload_type = 96;
    context.rtp_cfg.mtu = 1400;

    for (i = 1; i < argc; )
    {
        if (!strcmp(argv[i], "-i"))
        {
            context.rtp_cfg.ip = argv[i+1];
            i += 2;
        }
        else if (!strcmp(argv[i], "-p"))
        {
            context.rtp_cfg.port = atoi(argv[i+1]);
            i += 2;
        }
        else if (!strcmp(argv[i], "-pt"))
        {
            context.rtp_cfg.payload_type = atoi(argv[i+1]);
            i += 2;
        }
        else if (!strcmp(argv[i], "-rdt"))
        {
            context.rtp_cfg.protocol = LINDNET_TYPE_RDT;
            i += 1;
        }
        else if (!strcmp(argv[i], "-udp"))
        {
            context.rtp_cfg.protocol = LINDNET_TYPE_UDP;
            i += 1;
        }
        else if (!strcmp(argv[i], "-h264"))
        {
            context.rtp_cfg.venc_type = AV_ENC_TYPE_H264;
            context.venc_cfg.venc_type = AV_ENC_TYPE_H264;
            context.venc_cfg.profile = 1;
            i += 1;
        }
        else if (!strcmp(argv[i], "-h265"))
        {
            context.rtp_cfg.venc_type = AV_ENC_TYPE_H265;
            context.venc_cfg.venc_type = AV_ENC_TYPE_H265;
            context.venc_cfg.profile = 0;
            i += 1;
        }
        else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "-cap_size"))
        {
            context.camera_cfg.cap_width = atoi(argv[i+1]);
            context.camera_cfg.cap_height = atoi(argv[i+2]);
            i += 3;
        }
        else if (!strcmp(argv[i], "-vs") || !strcmp(argv[i], "-venc_size"))
        {
            context.venc_cfg.venc_width = atoi(argv[i+1]);
            context.venc_cfg.venc_height = atoi(argv[i+2]);
            i += 3;
        }
        else if (!strcmp(argv[i], "-br"))
        {
            context.venc_cfg.bitrate = atoi(argv[i+1]);
            i += 2;
        }
        else
        {
            i++;
        }
    }
    logi("ip: %s, port: %d, protocol: %d, mtu: %d, payload_type: %d",
        context.rtp_cfg.ip, context.rtp_cfg.port, context.rtp_cfg.protocol,
        context.rtp_cfg.mtu, context.rtp_cfg.payload_type);
    logi("video cap: [%dx%d], venc: [%dx%d], bitrate: %d(bps), enc_type: %d",
        context.camera_cfg.cap_width, context.camera_cfg.cap_height,
        context.venc_cfg.venc_width, context.venc_cfg.venc_height,
        context.venc_cfg.bitrate, context.rtp_cfg.venc_type);

    test_rtpsink(&context);

    return 0;
}

#ifdef MELIS_OS
FINSH_FUNCTION_EXPORT_ALIAS(main_melis, __cmd_sample_lindsink, lindsink sample);
#endif

